class Binding {
    constructor(id, path, scope, kind) {
        this.id = id;
        this.path = path;
        this.referenced = false;
        this.referencePaths = [];
    }
}

module.exports = class Scope {
    constructor(parentScope, path) {
        this.parent = parentScope;
        // bindings 是记录作用域中的每一个声明
        this.bindings = {};
        this.path = path;
        // scope 创建完成之后我们要扫描作用域中所有的声明，记录到 scope。
        // 这里要注意的是，因为遇到函数作用域要跳过遍历，因为它有自己独立的作用域
        path.traverse({
            VariableDeclarator: (childPath) => {
                this.registerBinding(childPath.node.id.name, childPath);
            },
            FunctionDeclaration: (childPath) => {
                childPath.skip();
                this.registerBinding(childPath.node.id.name, childPath);
            }
        })
        // 记录完 binding 之后，再扫描所有引用该 binding 的地方，也就是扫描所有的 identifier。
        path.traverse({
            Identifier: childPath => {
                if (!childPath.findParent(p => p.isVariableDeclarator() || p.isFunctionDeclaration())) {
                    const id = childPath.node.name;
                    const binding = this.getBinding(id);
                    if (binding) {
                        binding.referenced = true;
                        binding.referencePaths.push(childPath);
                    }
                }
            }
        })
    }

    //  添加声明 registerBinding
    registerBinding(id, path) {
        this.bindings[id] = new Binding(id, path);
    }

    // getOwnBing 是只从当前 scope 查找
    getOwnBinding(id) {
        return this.bindings[id];
    }

    // 查找声明 getBinding
    getBinding(id) {
        let res = this.getOwnBinding(id);
        if (res === undefined && this.parent) {
            res = this.parent.getBinding(id);
        }
        return res;
    }

    hasBinding(id) {
        return !!this.getBinding(id);
    }

}